class Person: # 定义一个类
    name = ''
    age = 0
    # self相当于this，代表实例化这个类的对象，__init__相当于构造函数
    def __init__(self,name,age): 
        self.name = name
        self.age = age
    
    # 静态方法
    @staticmethod
    def sm():
        print("静态方法 只能类调用")
    @classmethod
    def cm(cls):
        cls.age = 100
        print("类方法，用于直接操作类的属性：修改类的age为100")

# 创建一个Person类的对象
zhangsan = Person('',0)
lisi = Person('李四',12)
print(lisi.name,lisi.age)

Person.sm() # 调用静态方法
zhangsan.cm() # 调用类方法 类对象和实例对象都能调用
print(zhangsan.age)
'''
类的组成
    类属性      直接定义在类中，方法外的变量
    实例属性    定义在__init__方法中，使用self.的变量 
    实例方法    定义在类中的函数，自带self
    静态方法    使用装饰器@staticmethod修饰的方法 等同java中static方法
    类方法      使用装饰器@classmethod修饰的方法 用来直接操作类属性
'''

'''
动态绑定对象的属性和方法（跟js差不多）
'''
wangwu = Person('王五',13) # 实例化一个王五
# 动态绑定一个性别属性
wangwu.gender = '男'
# 动态绑定一个方法
def dynamic_fun(): # 当然要先定义
    print("动态方法")
wangwu.func1 = dynamic_fun  # 赋值
print(wangwu.gender) # 验证和调用
wangwu.func1()
# ------------------------------------------------------------------------
'''
封装：隐藏类的具体细节，暴露特定方法
权限控制：
    _开头的属性或方法：protected 只供自己和子类
    __开头的属性或方法：private 只能自己访问
    __开头结尾__：特殊方法
'''
class animal:
    _name = ''
    __gender = 0
    def _func1(self):
        pass
    def __func2(self):
        pass
    def show(self):
        self._func1()
        self.__func2()
        print(self._name,self.__gender)
cat = animal()
cat._name = '猫'
# cat.show()
print(cat._animal__gender) # 实际上，私有属性和方法，可以通过该形式访问：实例对象._类名__属性/方法
# 但是不推荐这么造

# ---------------------------------------------------------------------------
'''
get set
装饰器:方法作为属性使用，实际上就是让你的属性不能直接调用修改 功能等同java的getter setter
    @property == getter
    @属性.setter == setter
'''
class Student:
    def __init__(self,name):
        self.__name = name
    @property # getter
    def name(this):
        return this.__name
    @name.setter # setter
    def name(this,name):
        this.__name = name
stu1 = Student('学生')
# print(stu1.name) # 在没有init方法时，没有调用set前 没有该属性
stu1.name = '222'
print(stu1.name)
'''
继承
 py中是多继承,在类名后()内声明父类，子类中使用super().来获取父类属性和方法
 没有显示继承类时，默认继承object类

 子类继承父类，拥有父类public和protected成员
 子类可重写父类方法
 子类重写父类方法时，方法名需要相同，super().xxx调用父类方法
'''
class Car:
    _color=''
    _brand=''
    def __init__(self,color,brand):
        self._color = color
        self._brand = brand
    def _pipi():
        print("pipi")

class Bus(Car): # 集成 多个父类用,隔开
    _cap = 30
    def __init__(self, color, brand,cap):
        super().__init__(color, brand)
        self._cap = cap
    def passStation(self):
        print("pass")
bus401 = Bus('绿','奥迪',60)
bus401.passStation()
print(bus401._color,bus401._brand,bus401._cap)
'''
多继承，不同父类的方法用类名.调用
方法重写：子类重写父类同名方法
'''
class Father1:
    _attr1=0
    def __init__(self,attr1):
        self._attr1 = attr1
    def play1(self):
        pass
class Father2:
    _attr1 = 3
    def __init__(self,attr1):
        self._attr1 = attr1
    def play2(self):
        print("fu")
class Son(Father1,Father2):
    _attr_son = '孩子'
    def __init__(self, attr1):
        Father2.__init__(self,2)
        Father1.__init__(self,1) # 多个父类属性方法重名时，最后执行的为准
    # 方法重写
    def play2(self):
        super().play2()
        print('ff')
son = Son(30)
print(son._attr_son,son._attr1)
# son.play1()
# son.play2()
'''
多态 不同类中有同名方法即可
    与java不同，java的多态需要继承，这里只要方法同名就行
'''
def fun(obj):
    obj.play2()
fun(son)
fun(Father2(20))
'''
object类
    所有类中直接或间接的父类
    所有类都有object类的属性和方法
    __new__() 系统调用，用于创建对象
    __init__() 创建对象时手动调用，用于初始化对象属性值
    __str__() 对象的描述，返回值都是str类型，默认输出对象的内存地址
'''
# -----------------------------------------------------------------------

'''
object对象的特殊方法
+               __add__()                   加
-               __sub__()                   减
< <= ==         __lt__() __le__() __eq__()  比较
> >= !=         __gt__() __ge__() __ne__()  比较
* /             __mul__() __truediv__()     乘 非整除
% //            __mod__() __floordiv__()    余 整除
**              __pow__()                   幂

对象和类的特殊属性
obj.__dict__            对象的属性字典列表
obj.__class__           对象所属的类
class.__bases__         类的父类元组
class.__base__          类的父类
class.__mro__           类的层次结构
class._subclasses__()   类的子类列表
'''
'''
深拷贝 和 浅拷贝
变量赋值：形成两个变量，指向同一引用（这两个变量实际上是同一个人）
浅拷贝：对象包含的子对象内容不改变，例如车子A对象有个属性是个轮子对象，b = a，此时b车的轮子和a车的轮子是同一个
深拷贝：使用copy模块，deepcopy函数，会递归拷贝子对象的属性，子对象是不同的
copy.copy()是浅拷贝，但是返回新对象，deepcopy()深拷贝
'''
